﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web;
using uk.ac.soton.ses.DAL;

namespace uk.ac.soton.ses.WebControls
{
    public class ParameterReportingControl : CompositeDataBoundControl
    {
        private Table table = null;
        TableHeaderRow tr1 = null;
        TableRow tr2 = null;
        MaterialsMetadataContext dbcontext = null;

        private ExperimentParameter _parentParameter = null;
        public ExperimentParameter ParentParameter { get { return this._parentParameter; } set { this._parentParameter = value; } }

        protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
        {
            int count = 0;
            IEnumerable<ExperimentParameter> experimentParameters = null;
            this.dbcontext = HttpContext.Current.GetMaterialsDBContext();
            if (dataSource != null)
            {
                //We have a dataSource. Find out how many records we have.
                if (dataBinding)
                {
                    experimentParameters = dataSource.OfType<ExperimentParameter>();
                    count = experimentParameters.Count();
                }
                else
                {
                    //If we're not dataBinding, but we have a dataSource, then this must be a postback.
                    //We therefore just have a dummy datasource with no real data.
                    //Because we need data to recreate the controls, we cannot proceed any further.
                    Label lbl = new Label();
                    Controls.Add(lbl);
                    lbl.Text = "ParameterReportingControl should not be used on web pages that cause post backs.";
                    count = 0;
                    return count;
                }

                //If we don't have any records, we won't write anything to the report so we don't interfere with anything else that might be on the report
                if (count > 0)
                {
                    this.CreateNewTable();

                    //Work out if any parameters have children to decide if we're drawing a horizontal table
                    bool someParamsHaveChildren = this.SomeParamsHaveChildren(experimentParameters);
                    bool hasParent = this._parentParameter != null;
                    bool horizontalTable = hasParent && !someParamsHaveChildren;

                    //Add titles if necessary
                    if (horizontalTable)
                    {
                        this.AddTitlesToTable();
                    }

                    foreach (ExperimentParameter passedExperimentParameter in experimentParameters)
                    {
                        //We'll load the parameter from the database ourselves so we have it attached to a data context and then we can find related data
                        ExperimentParameter loadedExperimentParameter = dbcontext.ExperimentParameters.First(param => param.ID == passedExperimentParameter.ID);

                        //Find out some information about the parameter
                        IQueryable<ExperimentParameter> childParameters = dbcontext.GetExperimentChildParameters(loadedExperimentParameter.ID);
                        bool hasChildren = childParameters.Count() > 0;
                        bool someChildrenHaveChildren = this.SomeParamsHaveChildren(childParameters);
                        bool addValue = (horizontalTable || !hasChildren || someChildrenHaveChildren);
                        bool appendUnit = (!horizontalTable && (!hasChildren || someChildrenHaveChildren) && !string.IsNullOrEmpty(loadedExperimentParameter.Unit));

                        this.AddParameterDetailsToTable(addValue, appendUnit, loadedExperimentParameter);

                        if (hasChildren)
                        {
                            this.AddChildrenControl(loadedExperimentParameter, childParameters.OrderBy(param => param.Position).ThenBy(param => param.Name));
                        }

                        if (!horizontalTable)
                        {
                            //State 1: Top level parameter or middle level parameter with children
                            //State 1: Print names/values in new table, then data bind child control
                            //State 1: New table for each parameter

                            this.CreateNewTable();
                        }
                        else
                        {
                            //State 2: Bottom level parameter (no children and with a parent)
                            //State 2: Lookup titles using parent parameter, then print names/values in columns
                            //State 2: New column for each parameter
                        }
                    }
                }
            }

            return count;
        }

        private void CreateNewTable()
        {
            //Create a table
            table = new Table();
            table.CssClass = "ReportParametersTable";
            Controls.Add(table);

            //Create the rows
            tr1 = new TableHeaderRow();
            table.Rows.Add(tr1);
            tr2 = new TableRow();
            table.Rows.Add(tr2);
        }

        private void AddTitlesToTable()
        {
            //Add title controls:
            TableHeaderCell tdTitleValue = new TableHeaderCell();
            tdTitleValue.CssClass = "ReportParametersRowTitle";
            tr1.Cells.Add(tdTitleValue);
            TableHeaderCell tdTitleUnit = new TableHeaderCell();
            tdTitleUnit.CssClass = "ReportParametersRowTitle";
            tr2.Cells.Add(tdTitleUnit);
            Label lblTitleValue = new Label();
            tdTitleValue.Controls.Add(lblTitleValue);
            Label lblTitleUnit = new Label();
            tdTitleUnit.Controls.Add(lblTitleUnit);

            //Data bind title controls:
            lblTitleValue.Text = HttpUtility.HtmlEncode(this._parentParameter.Value);
            lblTitleUnit.Text = HttpUtility.HtmlEncode(this._parentParameter.Unit);
        }

        private void AddParameterDetailsToTable(bool addValue, bool appendUnit, ExperimentParameter parameterData)
        {
            //Add parameter name/value labels:
            TableHeaderCell tdParamName = new TableHeaderCell();
            tr1.Cells.Add(tdParamName);
            tdParamName.CssClass = "ReportParameterName";
            TableCell tdParamValue = new TableCell();
            tr2.Cells.Add(tdParamValue);
            tdParamValue.CssClass = "ReportParameterValue";
            Label lblParamName = new Label();
            tdParamName.Controls.Add(lblParamName); //Always add the control before changing data so the ViewState can be tracked
            Label lblParamValue = new Label();
            tdParamValue.Controls.Add(lblParamValue);//Always add the control before changing data so the ViewState can be tracked

            //Data bind the controls:
            lblParamName.Text = HttpUtility.HtmlEncode(parameterData.Name);

            //Add a unit to the title (if there are child params we don't do this as the sub-table contains the unit)
            if (appendUnit)
            {
                lblParamName.Text += HttpUtility.HtmlEncode(" (" + parameterData.Unit + ")");
            }

            if (addValue)
            {
                //Lookup the parameter value
                lblParamValue.Text = HttpUtility.HtmlEncode(parameterData.Value);
            }
        }

        private void AddChildrenControl(ExperimentParameter currentParameter, IEnumerable<ExperimentParameter> nextParameters)
        {
            //Add controls:
            TableHeaderCell tdParameterChildTitle = new TableHeaderCell(); //Note that this cell is not filled with anything, it is just to keep things lined up
            tr1.Cells.Add(tdParameterChildTitle);
            TableCell tdParameterChildren = new TableCell();
            tr2.Cells.Add(tdParameterChildren);
            ParameterReportingControl ctlParameterChildren = new ParameterReportingControl();
            tdParameterChildren.Controls.Add(ctlParameterChildren);

            //Data bind
            ctlParameterChildren.ParentParameter = currentParameter;
            ctlParameterChildren.DataSource = nextParameters;
            ctlParameterChildren.DataBind();
        }

        private bool SomeParamsHaveChildren(IEnumerable<ExperimentParameter> parameters)
        {
            bool someParamsHaveChildren = false;
            foreach (ExperimentParameter param in parameters)
            {
                someParamsHaveChildren = dbcontext.GetExperimentChildParameters(param.ID).Count() > 0;
                if (someParamsHaveChildren)
                {
                    break;
                }
            }
            return someParamsHaveChildren;
        }
    }
}
